/*
 * =====================================================================================
 *
 *       Filename:  nlm_state_machine.c
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  04/07/2011 10:32:20 AM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  YOUR NAME (), 
 *        Company:  
 *
 * =====================================================================================
 */

#include "config.h"

#include <aio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <rpc/rpc.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>

#define DBG_SUBSYS S_LIBINTERFACE

#include "lichstor.h"
#include "ynfs_conf.h"
#include "aiocb.h"
#include "attr.h"
#include "error.h"
#include "fh.h"
#include "job_dock.h"
#include "nlm_job_context.h"
#include "nlm_lkcache.h"
#include "net_global.h"
#include "nfs_conf.h"
#include "stat_cache.h"
#include "nlm_events.h"
#include "nlm_state_machine.h"
#include "nlm_nsm.h"
#include "../sock/sock_tcp.h"
#include "hostcache.h"
#include "readdir.h"
#include "sunrpc_proto.h"
#include "sunrpc_reply.h"
#include "xdr_nlm.h"
#include "sysy_conf.h"
#include "dbg.h"
#include <sys/socket.h>

/* write verifier */
extern worker_handler_t jobtracker;
extern int grace_period;

typedef enum {
        ACCEPT_STATE_OK, /* 0 */
        ACCEPT_STATE_ERROR, /* 1 */
} acceptstate_t;

int nlm_job2ip(job_t *job, char *host) 
{
	(void)job;
        #if 1
        //sprintf(host, "%s", inet_ntoa(((struct sockaddr_in*)&addr)->sin_addr));
        sprintf(host, "%s", "192.168.1.22");
#endif
	return 0;
}


int job2host(job_t *job, char *host, int type)
{
	int sd, ret;
	unsigned char *p;
	struct sockaddr addr;
	socklen_t addrlen;
	net_handle_t *nh;
	nh = &job->net;
	sd = nh->u.sd.sd;
	if ( type == REMOTE_HOST) {
		ret = getpeername(sd, &addr, &addrlen);
		if (unlikely(ret))
			DINFO("getpeername %s\n", strerror(errno));
		ret = getpeername(sd, &addr, &addrlen);
		if (unlikely(ret))
			DINFO("getpeername %s\n", strerror(errno));
	}else {
		ret = getsockname(sd, &addr, &addrlen);
		if (unlikely(ret))
			DINFO("getsockname %s\n", strerror(errno));
		ret = getsockname(sd, &addr, &addrlen);
		if (unlikely(ret))
			DINFO("getsockname %s\n", strerror(errno));
	}
	p = (unsigned char*)&(((struct sockaddr_in*)&addr)->sin_addr);
	sprintf(host, "%d.%d.%d.%d", *p, *(p+1), *(p+2), *(p+3));
//	sprintf(host, "%s", inet_ntoa(((struct sockaddr_in*)&addr)->sin_addr));
	DINFO("JOB2host host is %s\n", host);
	return 0;
}

int nlm_unmon_process()
{
        int ret;
        uint32_t port = 0;
        int sd;
        struct sockaddr addr;
        socklen_t addrlen;
        char host[64];
        memset(host, 0x0, 64);
        struct my_id my_id;
        struct sm_stat res;
	unsigned char *p __attribute__((unused));

        ret = tcp_sock_portlisten(&sd, 0, &port, 4, 0);
        if (unlikely(ret))
                GOTO(err_ret, ret);

        ret = getsockname(sd, &addr, &addrlen);
        if (unlikely(ret)) {
                ret = errno;
                GOTO(err_ret, ret);
        }

	p = (unsigned char*)&(((struct sockaddr_in*)&addr)->sin_addr);
#if 0
        sprintf(host, "%d.%d.%d.%d", *p, *(p+1), *(p+2), *(p+3));
#else
	gethostname(host, 64);
#if 0
        sprintf(host, "%s", "127.0.0.1");
#endif
#endif

        DINFO("unmon host is %s\n", host);

        my_id.len = strlen(host);
        ret = ymalloc((void**)&my_id.name, my_id.len);
        if (unlikely(ret))
                GOTO(err_ret, ret);
        memcpy(my_id.name, host, my_id.len);

        my_id.my_prog = NLM_PROGRAM;
        my_id.my_vers = NLM_VERSION;
        my_id.my_proc = 16;
#if 0
        ret = callrpc("127.0.0.1", 100024,
                        1,4 ,
                        (xdrproc_t)xdr_nsm_myid, (char*)&my_id,
                        (xdrproc_t)xdr_nsm_unmonres,  (char*)&res
                     );

        if (unlikely(ret))
                DINFO("unmont rpc failed %s\n", strerror(ret));
        if (res.state % 2) {
                DINFO("localnsm  is down\n")
        } else {
                DINFO("localnsm  is up\n")
        }
#endif
	CLIENT *client = clnt_create(host, 100024, 1, "tcp");
	if (client == NULL) {
		DINFO("client create error");
	}
	struct timeval timeout ={2, 0};
	enum clnt_stat stat = clnt_call(client, 4,
			(xdrproc_t)xdr_nsm_myid, (char*)&my_id,
			(xdrproc_t)xdr_nsm_unmonres,  (char*)&res,
			timeout
			);
	(void)stat;
	clnt_destroy(client);
        DINFO("unmon clnt_call %s\n", clnt_sperrno(stat));

        yfree((void**)&my_id.name);
err_ret:
        return ret;
}


int jobnlm2monid(nlmlock_t *lock, struct mon_id *monid, job_t *job)
{
        int ret;
        char host[64];
        memset(host, 0x0, 64);
        monid->len = lock->owner.len;

        ret = ymalloc((void**)&monid->name,monid->len);
        if (unlikely(ret))
                GOTO(err_ret, ret);
#if  1
        memcpy(monid->name, lock->owner.data, monid->len);
#endif

#if 0
        nlm_job2ip(job,host);
#endif
	(void)job;
	gethostname(host, 64);

        monid->my_id.len = strlen(host);
        ret = ymalloc((void**)&monid->my_id.name, monid->my_id.len);
        if (unlikely(ret))
                GOTO(err_mem, ret);
        memcpy(monid->my_id.name, host, monid->my_id.len);
	return 0;
err_mem:
        yfree((void**)&monid->name);
err_ret:
        return ret;
}
int jobnlm2mon(nlmlock_t *lock, struct mon *mon, job_t *job)
{
        int ret;
        ret = jobnlm2monid(lock, &mon->mon_id, job);
        if (unlikely(ret))
                GOTO(err_ret, ret);
	return 0;
err_ret:
        return ret;
}

int nlm_lock_process(hostmcache_t *hostcache, nlmlock_t *nlmlock, job_t *job)
{
        int ret;
        hostentry_t *hostentry, *retval = NULL;
        struct mon mon;
        struct sm_stat_res  res;
	char buf[64];

        ret = ymalloc((void**)&hostentry, sizeof(hostentry_t));
        if (unlikely(ret))
                GOTO(err_ret, ret);
        hostentry->len = nlmlock->owner.len;


        ret = ymalloc((void**)&hostentry->nm, hostentry->len);
        if (unlikely(ret))
                GOTO(err_mem, ret);
        memcpy(hostentry->nm, nlmlock->owner.data, nlmlock->owner.len);

	memset(buf, 0x0, 64);
	sprintf(buf, hostentry->nm, nlmlock->owner.len);
        DINFO("find the host, %s\n", buf);

        hostmcache_find(hostcache, hostentry, &retval);
        if ( retval ) {
                retval->lkn++;
                yfree((void**)&hostentry->nm);
                yfree((void**)&hostentry);
		nlmlk_mcache_unlock(&nlmlk_cache);
        } else {
		hostentry->lkn = 1;
                hostmcache_insert(hostcache, hostentry);
		nlmlk_mcache_unlock(&nlmlk_cache);
                /*
                 * call the sm_rpc
                 */
                jobnlm2mon(nlmlock, &mon, job);
	
                mon.mon_id.my_id.my_prog = NLM_PROGRAM;
                mon.mon_id.my_id.my_vers = NLM_VERSION;
                mon.mon_id.my_id.my_proc    = 16;

		memset(buf, 0x0, 64);
		gethostname(buf, 64);

		CLIENT *client = clnt_create(buf, 100024, 1, "tcp");
		if (client == NULL) {
			DINFO("client create error");
		}
		struct timeval timeout ={2, 0};
		enum clnt_stat stat = clnt_call(client, 2,
                        (xdrproc_t)xdr_nsm_monargs, (char*)&mon,
                        (xdrproc_t)xdr_nsm_monres,  (char*)&res,
			timeout
			);
		(void)stat;
		if (res.res_stat == STAT_SUCC) {
			DINFO("NSM agree to mon\n");
		} else {
			DINFO("NSM mon failed\n");
		}
                clnt_destroy(client);
        	DINFO("lock clnt_call %s\n", clnt_sperrno(stat));

#if 0
                DINFO("unfind the host, rpc call %s\n", buf);
                ret = callrpc("192.168.1.22", 100024, 1, 3,
                        (xdrproc_t)xdr_nsm_monargs, (char*)&mon,
                        (xdrproc_t)xdr_nsm_monres,  (char*)&res
                        );
                if (unlikely(ret))
                        DINFO("call rpc error %s\n", strerror(ret));
                if (res.res_stat == STAT_SUCC) {
                        DINFO("mon sucess\n");
                }
                else  {
                        DINFO("mon failed\n");
                }
#endif
        }
        return 0;
err_mem:
        yfree((void**)&hostentry);
err_ret:
	nlmlk_mcache_unlock(&nlmlk_cache);
        return ret;
}
int nlm_unlock_process(hostmcache_t *hostcache, nlmlock_t *nlmlock, job_t *job, int num)
{

        int ret;
        hostentry_t *hostentry, *retval = NULL;
        struct mon_id mon_id;
        struct sm_stat res;
	char buf[64];

        ret = ymalloc((void**)&hostentry, sizeof(hostentry_t));
        if (unlikely(ret))
                GOTO(err_ret, ret);
        hostentry->len = nlmlock->owner.len;

        ret = ymalloc((void**)&hostentry->nm, hostentry->len);
        if (unlikely(ret))
                GOTO(err_mem, ret);
        memcpy(hostentry->nm, nlmlock->owner.data, nlmlock->owner.len);
	
	memset(buf, 0x0, 64);
	memcpy(buf, nlmlock->owner.data, nlmlock->owner.len);
	DINFO("unlock host %s\n", buf);

        hostmcache_find(hostcache, hostentry, &retval);
        if ( retval ) {
                retval->lkn = retval->lkn-num;
                if (retval->lkn == 0) {
                        hostmcache_delete(hostcache, hostentry, &retval);
			nlmlk_mcache_unlock(&nlmlk_cache);
                        yfree((void**)&retval->nm);
                        yfree((void**)&retval);
                        /*
                         * rpc call
                         */
                        jobnlm2monid(nlmlock, &mon_id, job);
                        mon_id.my_id.my_prog = NLM_PROGRAM;
                        mon_id.my_id.my_vers = NLM_VERSION;
                        mon_id.my_id.my_proc    = 16;

			memset(buf, 0x0, 64);
			gethostname(buf, 64);
			CLIENT *client = clnt_create(buf, 100024, 1, "tcp");
			if (client == NULL) {
				DINFO("client create error");
			}
			struct timeval timeout ={2, 0};
			enum clnt_stat stat = clnt_call(client, 3,
					(xdrproc_t)xdr_nsm_unmonargs, (char*)&mon_id,
					(xdrproc_t)xdr_nsm_unmonres,  (char*)&res,
					timeout
					);
			(void)stat;
			clnt_destroy(client);
			DINFO("unlock clnt_call %s\n", clnt_sperrno(stat));
#if 0
                        ret = callrpc("127.0.0.1", 100024,
                                        1, 3,
                                        (xdrproc_t)xdr_nsm_unmonargs, (char*)&mon_id,
                                        (xdrproc_t)xdr_nsm_unmonres,  (char*)&res
                               );
                        if (unlikely(ret))
                                DWARN("call rpc error %s\n", strerror(ret));
#endif
                } else {
			nlmlk_mcache_unlock(&nlmlk_cache);
		}
                yfree((void**)&hostentry->nm);
                yfree((void**)&hostentry);
        } else {
		nlmlk_mcache_unlock(&nlmlk_cache);
                DWARN("host cache NULL ,why happen\n");
        }
        return 0;
err_mem:
        yfree((void**)&hostentry);
err_ret:
	nlmlk_mcache_unlock(&nlmlk_cache);
        return ret;
}

int nlm_null_svc(job_t *job)
{
        int ret;



        ret = sunrpc_reply_prep(job, NULL, NULL, ACCEPT_STATE_OK);
        if (unlikely(ret))
                GOTO(err_free, ret);

        ret = sunrpc_reply_send(job, NULL, FREE_JOB);
        if (unlikely(ret))
                GOTO(err_ret, ret);

        return 0;
err_free:
err_ret:
        return ret;
}

int nlm4_test_svc(job_t *job)
{
        (void)job;

        int ret, done = 0;
        nlm_job_context_t *context;
        nlm_testargs   *args;
        nlm_testres res;
        nlmlock_t *colision,*nlmlock;

        fileid_t *fileid;

        context = (nlm_job_context_t *)job->context;
        args = &context->arg.testargs;
        fileid = (fileid_t *)args->alock.fh.val;

        DINFO("NLM_TEST fileid %llu_v%u exclsive %d\n", (LLU)fileid->id, fileid->version, (int)args->exclusive);
        ymalloc((void**)&nlmlock, sizeof(nlmlock_t));
        YASSERT(NULL!=nlmlock);
        while (done == 0) {
                switch (job->status) {
                        default:
                         /* lock cache
                          * see try to find the lock, 
                         */
                        testargs2nlmlock(args, nlmlock, job);

                        nlmlk_mcache_lock(&nlmlk_cache);

                        ret = nlmlk_mcache_colison(&nlmlk_cache, nlmlock, &colision);
                        if (colision) {
                                nlmlock2testres(&res, colision);
                                res.test_stat.status = NLM4_DENIED;
                                /*
                                 * free nlmlock
                                 */
                        	nlmlk_mcache_unlock(&nlmlk_cache);
                                free_nlmlock(nlmlock);
                        } else {
                                /*
                                 * insert the lock into the cache
                                 */
                                nlmlk_mcache_insert(&nlmlk_cache, nlmlock);
                                res.test_stat.status =  NLM4_GRANTED;
                                nlm_lock_process(&hostcache, nlmlock, job);
                        }
                        /* cookies
                        */
                        res.cookies.len = args->cookies.len;
                        ymalloc((void**)&res.cookies.data, args->cookies.len);
                        YASSERT(NULL != res.cookies.data);
                        memcpy(res.cookies.data, args->cookies.data, args->cookies.len);

                        FREE_ARGS(nlm_test);

                        SUNRPC_REPLY_OK(xdr_nlm_testres, FREE_JOB, ACCEPT_STATE_OK);
                        /*
                         *free res 
                         */
                        yfree((void**)&res.cookies.data);

                        /* mem leak !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                         * must free res;
                         * may be must free nlmlock
                         */
                        done = 1;
                }
        }
        return 0;
err_rep:
        /*
         * free res
         */
        SUNRPC_REPLY_ERROR(xdr_nlm_testres, FREE_JOB, ACCEPT_STATE_OK);
        yfree((void**)&res.cookies.data);
err_ret:
        return ret;
}

int nlm4_lock_svc(job_t *job)
{
        (void)job;

        int ret, done = 0;
        nlm_job_context_t *context;
        nlm_lockargs *args;

        nlm_res res;
        nlmlock_t *colision,*nlmlock;

        fileid_t *fileid;

        context = (nlm_job_context_t *)job->context;
        args = &context->arg.lockargs;
        fileid = (fileid_t *)args->alock.fh.val;

        DINFO("NLM_LOCK_SVC fileid %llu_v%u offset %llu len %llu svid %u\n", (LLU)fileid->id, fileid->version,/* (int)args->exclusive, (int)args->state, */(LLU)args->alock.l_offset, (LLU)args->alock.l_len,args->alock.svid);
        ymalloc((void**)&nlmlock, sizeof(nlmlock_t));
        YASSERT(NULL!=nlmlock);
        while (done == 0) {
                switch (job->status) {
                        default:
                         /* lock cache
                          * simple impl, not block, state not process
                         */
                        lockargs2nlmlock(args, nlmlock, job);


                        if ( 0 == grace_period ) {

                        	nlmlk_mcache_lock(&nlmlk_cache);
                                ret = nlmlk_mcache_colison(&nlmlk_cache, nlmlock, &colision);
                                if (colision) {
					DINFO("lock_svc colison\n");
                                        if (args->block)
                                                res.stat = NLM4_BLOCKED;
                                        else
                                                res.stat = NLM4_DENIED;
                                        /* free nlmlock
                                        */
                                        if (nlmlock->svid == colision->svid)
                                                res.stat = NLM4_GRANTED;
					nlmlk_mcache_unlock(&nlmlk_cache);
                                        free_nlmlock(nlmlock);
                                } else {
                                        /*insert the lock into the cache
                                         */
					DINFO("lock_svc new lock\n");
                                        nlmlk_mcache_insert(&nlmlk_cache, nlmlock);
                                        res.stat = NLM4_GRANTED;
                                        /* if it is the first lock of the host, we mon
                                        */
                                        nlm_lock_process(&hostcache, nlmlock, job);
                                }
                        } else {
                                if (args->reclaim == 1) {
					nlmlk_mcache_lock(&nlmlk_cache);
                                        ret = nlmlk_mcache_colison(&nlmlk_cache, nlmlock, &colision);
                                        if (colision) {
                                                /*this seem could not happen
                                                 */
                                                if (args->block)
                                                        res.stat = NLM4_BLOCKED;
                                                else
                                                        res.stat = NLM4_DENIED;

                                                /* free nlmlock
                                                */
                                                if (nlmlock->svid == colision->svid)
                                                        res.stat = NLM4_GRANTED;
                                                free_nlmlock(nlmlock);
						nlmlk_mcache_unlock(&nlmlk_cache);
                                        } else {
                                                /* insert the lock into the cache
                                                 */
                                                DINFO("regot the locker\n");
                                                nlmlk_mcache_insert(&nlmlk_cache, nlmlock);
                                                res.stat = NLM4_GRANTED;
                                                /* if it is the first lock of the host, we mon
                                                */
                                                nlm_lock_process(&hostcache, nlmlock, job);
                                        }
                                } else {
                                        res.stat = NLM4_DENIED_GRACE_PERIOD;
                                        /* free nlmlock
                                        */
                                        free_nlmlock(nlmlock);
                                }
                        }

                        /*cookies
                         */
                        res.cookies.len = args->cookies.len;
                        ymalloc((void**)&res.cookies.data, args->cookies.len);
                        YASSERT(NULL != res.cookies.data);
                        memcpy(res.cookies.data, args->cookies.data, args->cookies.len);
                        FREE_ARGS(nlm_lock);
                        SUNRPC_REPLY_OK(xdr_nlm_res, FREE_JOB, ACCEPT_STATE_OK);

                        yfree((void**)&res.cookies.data);
                        /*
                         * mem leak
                         * must free res;
                         * may be must free nlmlock
                         */
                        done = 1;
                }
        }
        return 0;
err_rep:
        SUNRPC_REPLY_ERROR(xdr_nlm_res, FREE_JOB, ACCEPT_STATE_OK);
        yfree((void**)&res.cookies.data);
err_ret:
        return ret;
}

int nlm4_unlock_svc(job_t *job)
{
        (void)job;

        int ret, done = 0,num=0;
        nlm_job_context_t *context;
        nlm_unlockargs *args;


        nlm_res res;
        nlmlock_t *retval,*nlmlock;
        fileid_t *fileid;

        context = (nlm_job_context_t *)job->context;
        args = &context->arg.unlockargs;
        fileid = (fileid_t *)args->alock.fh.val;

        DINFO("NLM_UNLOCK fileid %llu_v%u offset %llu --len %llu svid %u\n", (LLU)fileid->id, fileid->version,
	      (LLU)args->alock.l_offset, (LLU)args->alock.l_len, args->alock.svid);
        ymalloc((void**)&nlmlock, sizeof(nlmlock_t));
        YASSERT(NULL!=nlmlock);
        while (done == 0) {
                switch (job->status) {
                        default:
                         /* lock cache
                          * simple impl, not block, state not process
                         */

                        unlockargs2nlmlock(args, nlmlock, job);

                        nlmlk_mcache_lock(&nlmlk_cache);

                        ret = nlmlk_mcache_find(&nlmlk_cache, nlmlock, &retval);
                        if (retval) {
                                res.stat = NLM4_GRANTED;
                                /*two case
                                 *1. not the good svid ; there must be a coding error
                                 *2. the good svid
                                 */
                                DINFO("unlock in the cache, will unlock\n");
                                if (retval->svid  ==  nlmlock->svid) {
                                        ret = nlmlk_mcache_delete(&nlmlk_cache, nlmlock, &retval);
                                        nlm_unlock_process(&hostcache, nlmlock, job, 1);
                                        YASSERT((ret == 0) && (NULL != retval));
                                        /* !!! should free retval mem_leak
                                        */
                                        free_nlmlock(retval);
                                } else {
                                        nlmlk_mcache_unlock(&nlmlk_cache);
                                }
                        } else {
                                /*we still GRANTED, while there is no lock
                                 *there two case:
                                 *1. really not find 
                                 *2. may be the app crash,, and the offset wiil be..
                                */
                                if (nlmlock->l_len == 0 && nlmlock->l_offset == 0) {
                                        ret = nlmlk_mcache_clear(&nlmlk_cache, nlmlock, &num);
                                        if (num) {
                                                nlm_unlock_process(&hostcache, nlmlock, job, num);
                                        } else {
	                                        nlmlk_mcache_unlock(&nlmlk_cache);
                                        }
                                } else {
                                        nlmlk_mcache_unlock(&nlmlk_cache);
                                }
                                res.stat = NLM4_GRANTED;
                        }

                        /* cookies
                         */
                        res.cookies.len = args->cookies.len;
                        ymalloc((void**)&res.cookies.data, args->cookies.len);
                        YASSERT(NULL != res.cookies.data);
                        memcpy(res.cookies.data, args->cookies.data, args->cookies.len);

                        FREE_ARGS(nlm_unlock);
                        free_nlmlock(nlmlock);

                        SUNRPC_REPLY_OK(xdr_nlm_res, FREE_JOB, ACCEPT_STATE_OK);

                        /* mem leak !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                         * must free res;
                         * may be must free nlmlock
                         */
                        yfree((void**)&res.cookies.data);
                        done = 1;
                }
        }
        return 0;
err_rep:
        SUNRPC_REPLY_ERROR(xdr_nlm_res, FREE_JOB, ACCEPT_STATE_OK);
        yfree((void**)&res.cookies.data);
err_ret:
        return ret;
}

int nlm4_notify_svc(job_t *job)
{
        (void)job;

        int done = 0;
        nlm_job_context_t *context;
        nlm_notifyargs *args;
	hostentry_t hostentry,*retval;
        char host[64];

        context = (nlm_job_context_t *)job->context;
        args = &context->arg.notifyargs;

        memset(host, 0x0, 64);
        memcpy(host, args->cookies.data, args->cookies.len);
        DINFO("NLM4_NOTIFY_SVC host %s, state %d\n", host, (int)args->state);
        while (done == 0) {
                switch (job->status) {
                        default:
                        nlmlk_mcache_lock(&nlmlk_cache);
                        nlmlk_del_host(&nlmlk_cache, (unsigned char*)host, args->state);
			ymalloc((void**)&hostentry.nm, args->cookies.len);
			memcpy(hostentry.nm, args->cookies.data, args->cookies.len);
			hostentry.len = args->cookies.len;
			hostmcache_delete(&hostcache, &hostentry, &retval);
                        nlmlk_mcache_unlock(&nlmlk_cache);
			/*
			*/
			if (retval) {
				DINFO("del the host %s\n", host);
				yfree((void**)&retval->nm);
			} else {
				DINFO("error , can not find the host %s\n", host);
			}
			yfree((void**)&hostentry.nm);
                        //SUNRPC_REPLY_OK(NULL, FREE_JOB, ACCEPT_STATE_OK);
                        FREE_ARGS(nlm_notify);
                        job_destroy(job);
                        done = 1;
                }
        }
        return 0;
#if 0
err_rep:
        SUNRPC_REPLY_ERROR(xdr_nlm_res, FREE_JOB, ACCEPT_STATE_OK);
#endif
}

int nlm4_granted_svc(job_t *job)
{
        (void)job;

        return 0;
}
